﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Storage;
namespace FinalGame
{
    public class Terrain : VisibleObject
    {
        private int terrainWidth = 4;
        private int terrainHeight = 3;
        private int[] indices;
        VertexPositionNormalTexture[] vertices;
        private float[,] heightData;
        private Effect effect;
        VertexBuffer myVertexBuffer;
        IndexBuffer myIndexBuffer;
        Texture2D grassTexture;

        public Terrain(Vector3 Position,Vector3 Rotation, Vector3 Scale ,GraphicsDevice graphicsDevice,Effect effect,Texture2D texture)
            : base(graphicsDevice)
        {
            this.Position = Position;
            this.Rotation = Rotation;
            this.Scale = Scale;
            this.effect = effect;
            this.grassTexture = texture;
            //LoadHeightData();
            //SetUpVertices();
            //SetUpIndices();

        }
       

        public void LoadMapFromTexture(Texture2D heightMap)
        {
            terrainWidth = heightMap.Width;
            terrainHeight = heightMap.Height;

            Color[] heightMapColors = new Color[terrainWidth * terrainHeight];
            heightMap.GetData(heightMapColors);

            heightData = new float[terrainWidth, terrainHeight];
            for (int x = 0; x < terrainWidth; x++)
                for (int y = 0; y < terrainHeight; y++)
                    heightData[x, y] = heightMapColors[x + y * terrainWidth].R / 5.0f;
            SetUpVertices();
            SetUpIndices();
            CalculateNormals();
           // CopyToBuffers();
          
           

           
            
            
           
           
               

        }
        private void SetUpIndices()
        {
            indices = new int[(terrainWidth - 1) * (terrainHeight - 1) * 6];
            int counter = 0;
            for (int y = 0; y < terrainHeight - 1; y++)
            {
                for (int x = 0; x < terrainWidth - 1; x++)
                {
                    int lowerLeft = x + y * terrainWidth;
                    int lowerRight = (x + 1) + y * terrainWidth;
                    int topLeft = x + (y + 1) * terrainWidth;
                    int topRight = (x + 1) + (y + 1) * terrainWidth;

                    indices[counter++] = topLeft;
                    indices[counter++] = lowerRight;
                    indices[counter++] = lowerLeft;

                    indices[counter++] = topLeft;
                    indices[counter++] = topRight;
                    indices[counter++] = lowerRight;
                }
            }
        }
       
        private void LoadHeightData()
        {
            heightData = new float[4, 3];
            heightData[0, 0] = 0;
            heightData[1, 0] = 0;
            heightData[2, 0] = 0;
            heightData[3, 0] = 0;

            heightData[0, 1] = 0.5f;
            heightData[1, 1] = 0;
            heightData[2, 1] = -1.0f;
            heightData[3, 1] = 0.2f;

            heightData[0, 2] = 1.0f;
            heightData[1, 2] = 1.2f;
            heightData[2, 2] = 0.8f;
            heightData[3, 2] = 0;
        }

        private void SetUpVertices()
        {
            float minHeight = float.MaxValue;
            float maxHeight = float.MinValue;
            for (int x = 0; x < terrainWidth; x++)
            {
                for (int y = 0; y < terrainHeight; y++)
                {
                    if (heightData[x, y] < minHeight)
                        minHeight = heightData[x, y];
                    if (heightData[x, y] > maxHeight)
                        maxHeight = heightData[x, y];
                }
            }
            vertices = new VertexPositionNormalTexture[terrainWidth * terrainHeight];
            for (int x = 0; x < terrainWidth; x++)
            {
                for (int y = 0; y < terrainHeight; y++)
                {
                    vertices[x + y * terrainWidth].Position = (new Vector3(x, heightData[x,y], -y))*4;
                    vertices[x + y * terrainWidth].Normal = new Vector3(0, 0, 0);
                    vertices[x + y * terrainWidth].TextureCoordinate.X = (float)x / 30.0f;
                    vertices[x + y * terrainWidth].TextureCoordinate.Y = (float)y / 30.0f;
                }
            }
        }
        private void CalculateNormals()
        {
            for (int i = 0; i < vertices.Length; i++)
                vertices[i].Normal = new Vector3(0, 0, 0);
            for (int i = 0; i < indices.Length / 3; i++)
            {
                int index1 = indices[i * 3];
                int index2 = indices[i * 3 + 1];
                int index3 = indices[i * 3 + 2];

                Vector3 side1 = vertices[index1].Position - vertices[index3].Position;
                Vector3 side2 = vertices[index1].Position - vertices[index2].Position;
                Vector3 normal = Vector3.Cross(side1, side2);

                vertices[index1].Normal += normal;
                vertices[index2].Normal += normal;
                vertices[index3].Normal += normal;
            }
            for (int i = 0; i < vertices.Length; i++)
                vertices[i].Normal.Normalize();

        }

       
        public void Draw(Matrix View, Matrix Projection)
        {

            GraphicsDevice.VertexDeclaration = new VertexDeclaration(GraphicsDevice, VertexPositionNormalTexture.VertexElements);
            
            Matrix baseWorld =  Matrix.CreateScale(Scale)
                * Matrix.CreateFromYawPitchRoll(Rotation.Y, Rotation.X, Rotation.Z)
                * Matrix.CreateTranslation(Position);
            effect.Parameters["xWorld"].SetValue(baseWorld);
            effect.Parameters["xView"].SetValue(View);
            PresentationParameters pp = GraphicsDevice.PresentationParameters;
            float aspect = (float)pp.BackBufferWidth /
                                (float)pp.BackBufferHeight;
            effect.Parameters["xProjection"].SetValue(Projection);
            //effect.CurrentTechnique = effect.Techniques["Colored"];
            Vector3 lightDirection = new Vector3(1.0f, -1.0f, -1.0f);
            lightDirection.Normalize();
            effect.CurrentTechnique = effect.Techniques["Textured"];
            effect.Parameters["xTexture"].SetValue(grassTexture);
            effect.Parameters["xLightDirection"].SetValue(lightDirection);
            effect.Parameters["xAmbient"].SetValue(0.1f); effect.Parameters["xEnableLighting"].SetValue(true);   
            effect.Begin();
            foreach (EffectPass pass in effect.CurrentTechnique.Passes)
            {
                pass.Begin();
                
                GraphicsDevice.DrawUserIndexedPrimitives<VertexPositionNormalTexture>(PrimitiveType.TriangleList,
                   vertices, 0, vertices.Length, indices, 0, indices.Length / 3);
                pass.End();
            }
            effect.End();
        }
    }
}
